Debugger = require("SharedLibs.Debugger");
TableUtil = require("SharedLibs.Utils.TableUtil");

--[[
1. 使用TickedQueue.Enqueue()将一个对象加入TickedQueue
2. isStopped返回true时，对象会自动从Tikcing队列里移除（不是立刻执行）
3. isInQueue返回当前对象是否在 TickedQueue 里
]]
local TickedQueue = {}
TickedQueue.__index = TickedQueue
TickedQueue.ClassName = "TickedQueue"

function TickedQueue.new()
	local self = setmetatable({}, TickedQueue)

	--- List of ITickable
	self._aliveTickers = {};
	self.__newAddedTickers = {};

	self.__inTraverse = false;

	return self
end

function TickedQueue:Clear()
	Debugger.Assert(not self.__inTraverse);
	if nil == self._aliveTickers then return; end;

	self._aliveTickers = {};
	self.__newAddedTickers = {};
end

function TickedQueue:Update()
	self.__inTraverse = true;

	if #self.__newAddedTickers > 0 then 
		for i, ticker in ipairs(self.__newAddedTickers) do
			table.insert(self._aliveTickers, ticker); 
		end
		
		TableUtil.ClearArray(self.__newAddedTickers);
	end;	

	local nAliveCount = #self._aliveTickers;
	local curTicker = nil;
	local tickers = self._aliveTickers;
	
	--- Lua的loop索引i是无法修改的，所以这里需要自己记录索引（从而可以修改）
	local index=1;
	local count = nAliveCount;
	for i=1, nAliveCount do
		curTicker = tickers[index];
		curTicker:Update();
		local bIsDead = curTicker.isStopped;

		if not bIsDead then 
			index = index+1;		
			if index > count then break; end;
			goto continue;
		end;

		if index < count then
			-- Swap with last element
			tickers[index] = tickers[count];
			index = index - 1;
			count = count - 1;

		elseif index == count then
			count = count - 1;

		else 
			Debugger.Assert(false);
		end;
		
		--- 移除末尾的Ticker
		table.remove(tickers);
		curTicker.isInQueue = false;
		--- 通知LeaveQueue事件。如果一个对象被Pooling了
		--- 可以在这个事件里回收对象。
		if curTicker.OnLeaveQueue then 
			curTicker:OnLeaveQueue();
		end
		
		index = index+1;		
		if index > count then break; end;
		
	    ::continue::
	end

end

function TickedQueue:Enqueue(ticker)
	if not ticker.isInQueue then
		if Debugger.developMode then 
			Debugger.Assert(not ticker.isStopped);
			Debugger.Assert(not self:_isInQueue(ticker));			
		end
		ticker.isInQueue = true;

		if self.__inTraverse then
			table.insert(self.__newAddedTickers, ticker);
		else 
			table.insert(self._aliveTickers, ticker);

		end

	else
		if Debugger.developMode then 
			Debugger.Assert(self:_isInQueue(ticker));			
		end
	end
end

function TickedQueue:_isInQueue(ticker)
	Debugger.Assert(ticker ~= nil);

	local bInQueue = TableUtil.ArrayContains(self.__newAddedTickers, ticker)
		or TableUtil.ArrayContains(self._aliveTickers, ticker);

	Debugger.Assert(ticker.isInQueue == bInQueue);
	return bInQueue;
end

return TickedQueue;

